package com.supermap;

import com.supermap.consts.AttrConsts;
import com.supermap.data.*;
import com.supermap.dialogs.DatasetGridAddToSceneDialog;
import com.supermap.dialogs.InputNameDialog;
import com.supermap.mapping.*;
import com.supermap.mouseListeners.Layer3DsTreeMouseListener;
import com.supermap.mouseListeners.LayersTreeMouseListener;
import com.supermap.mouseListeners.MapControlMouseListener;
import com.supermap.realspace.*;
import com.supermap.ui.Action;
import com.supermap.ui.*;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Random;

public class Helper {
    /**
     * 获取默认间距
     *
     * @return 默认间距
     */
    public static Insets DefaultInsets = new Insets(2, 2, 2, 2);

    /**
     * 获取资源文件中的图标
     *
     * @param name 图标文件名
     * @return 图标对象
     */
    public static ImageIcon getImageIconFromResources(String name) {
        return new ImageIcon("Resources/" + name);
    }


    /**
     * 打开工作空间文件
     *
     * @param parent        当前窗口
     * @param workspaceTree 工作空间树
     */
    public static void openWorkspaceFile(Frame parent, WorkspaceTree workspaceTree) {
        FileDialog openFileDialog = new FileDialog(parent, "打开工作空间", FileDialog.LOAD);
        String workspaceFilePath = Helper.getFilePathFromFileDialog(openFileDialog, AttrConsts.WORKSPACE_FILTER);
        if (workspaceFilePath == null) {
            return;
        }

        // 创建工作空间连接信息
        WorkspaceConnectionInfo workspaceConnectionInfo = new WorkspaceConnectionInfo(workspaceFilePath);
        Workspace workspace = workspaceTree.getWorkspace();
        if (workspace != null) {
            workspace.close();
        }
        if (workspace == null) {
            return;
        }
        if (!workspace.open(workspaceConnectionInfo)) {
            JOptionPane.showMessageDialog(parent, "打开工作空间失败！", "打开工作空间操作结果", JOptionPane.ERROR_MESSAGE);
            return;
        }

        workspaceTree.setWorkspace(workspace);

        if (parent instanceof MainFrame) {
            MainFrame mainFrame = (MainFrame) parent;
            mainFrame.queryMenu.setEnabled(true);
            mainFrame.dataOperateMenu.setEnabled(true);
            mainFrame.projMenu.setEnabled(true);
            mainFrame.analystMenu.setEnabled(true);
            mainFrame.spatialStatisticsMenu.setEnabled(true);
        }
    }


    /**
     * 从文件对话框中获取选择的文件路径
     *
     * @param fileDialog 文件对话框
     * @param fileFilter 文件类型过滤
     * @return 选择文件路径
     */
    public static String getFilePathFromFileDialog(FileDialog fileDialog, String fileFilter) {
        try {
            fileDialog.setFile(fileFilter);
            fileDialog.setVisible(true);

            String fileName = fileDialog.getFile();
            if (fileName == null) {
                return null;
            }

            String directory = fileDialog.getDirectory();
            return directory + fileName;
        } finally {
            fileDialog.dispose();
        }
    }

    /**
     * 填充属性表
     *
     * @param recordset 矢量数据集
     * @param table     属性表
     */
    public static void loadTabular(Recordset recordset, JTable table) {
        DefaultTableModel tableModel = new DefaultTableModel();

        // 准备表头
        int fieldCount = recordset.getFieldCount();
        String[] columnNames = new String[fieldCount];
        FieldInfos fieldInfos = recordset.getFieldInfos();
        for (int i = 0; i < fieldCount; i++) {
            String caption = fieldInfos.get(i).getCaption();
            columnNames[i] = caption;
        }
        tableModel.setColumnIdentifiers(columnNames);

        // 准备表值
        int recordCount = recordset.getRecordCount();
        for (int i = 0; i < recordCount; i++) {
            Object[] tableData = new Object[fieldCount];
            for (int j = 0; j < fieldCount; j++) {
                tableData[j] = recordset.getFieldValue(j);
            }
            tableModel.addRow(tableData);
            recordset.moveNext();
        }
        recordset.close();

        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        table.setModel(tableModel);
        // 表列宽
        TableColumnModel columnModel = table.getColumnModel();
        for (int i = 0; i < columnModel.getColumnCount(); i++) {
            TableColumn column = columnModel.getColumn(i);
            column.setMinWidth(80);
        }
    }

    /**
     * 从树中获取当前选中节点
     *
     * @param tree 树
     * @return 当前选中节点
     */
    public static TreeNodeData getSelectedTreeNode(JTree tree) {
        Object lastSelectedPathComponent = tree.getLastSelectedPathComponent();
        if (lastSelectedPathComponent instanceof DefaultMutableTreeNode) {
            Object userObject = ((DefaultMutableTreeNode) lastSelectedPathComponent).getUserObject();
            if (userObject instanceof TreeNodeData) {
                return (TreeNodeData) userObject;
            }
        }
        return null;
    }

    /**
     * 判断当前地图的文本图层是否处于可编辑状态
     *
     * @param layers 当前地图的图层集
     * @return 当前地图的文本图层是否处于可编辑状态
     */
    public static boolean isEditableTextLayer(Layers layers) {
        if (layers == null || layers.getCount() == 0) {
            return false;
        }

        int layersCount = layers.getCount();
        for (int i = 0; i < layersCount; i++) {
            Layer layer = layers.get(i);
            Dataset dataset = layer.getDataset();
            DatasetType datasetType = dataset.getType();
            if (datasetType == DatasetType.TEXT && layer.isEditable()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断当前地图的点图层是否处于可编辑状态
     *
     * @param layers 当前地图的图层集
     * @return 当前地图的文本图层是否处于可编辑状态
     */
    public static boolean isEditablePointLayer(Layers layers) {
        if (layers == null || layers.getCount() == 0) {
            return false;
        }

        int layersCount = layers.getCount();
        for (int i = 0; i < layersCount; i++) {
            Layer layer = layers.get(i);
            Dataset dataset = layer.getDataset();
            DatasetType datasetType = dataset.getType();
            if (datasetType == DatasetType.POINT && layer.isEditable()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断当前地图的线图层是否处于可编辑状态
     *
     * @param layers 当前地图的图层集
     * @return 当前地图的文本图层是否处于可编辑状态
     */
    public static boolean isEditableLineLayer(Layers layers) {
        if (layers == null || layers.getCount() == 0) {
            return false;
        }

        int layersCount = layers.getCount();
        for (int i = 0; i < layersCount; i++) {
            Layer layer = layers.get(i);
            Dataset dataset = layer.getDataset();
            DatasetType datasetType = dataset.getType();
            if (datasetType == DatasetType.LINE && layer.isEditable()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 判断当前地图的面图层是否处于可编辑状态
     *
     * @param layers 当前地图的图层集
     * @return 当前地图的文本图层是否处于可编辑状态
     */
    public static boolean isEditablePolygonLayer(Layers layers) {
        if (layers == null || layers.getCount() == 0) {
            return false;
        }

        int layersCount = layers.getCount();
        for (int i = 0; i < layersCount; i++) {
            Layer layer = layers.get(i);
            Dataset dataset = layer.getDataset();
            DatasetType datasetType = dataset.getType();
            if (datasetType == DatasetType.REGION && layer.isEditable()) {
                return true;
            }
        }

        return false;
    }

    public static void updateComponentsEnabled(Component[] components, boolean isEnabled) {
        if (components != null && components.length > 0) {
            for (Component component : components) {
                component.setEnabled(isEnabled);
            }
        }
    }

    public static MapControl createMapControl(String mapName, JTabbedPane mainPane, WorkspaceTree workspaceTree, JLabel mapScaledLbl) {
        if (mapName == null || mapName.equals(AttrConsts.EMPTY)) {
            Component[] components = mainPane.getComponents();
            mapName = "未命名地图";
            if (components != null && components.length > 0) {
                int mapCount = 0;
                for (Component component : components) {
                    if (component instanceof MapControl) {
                        mapCount++;
                    }
                }
                if (mapCount > 0) {
                    mapName = mapName + "_" + mapCount;
                }
            }
        }
        MapControl mapControl = new MapControl(workspaceTree.getWorkspace());
        mapControl.addMouseListener(new MapControlMouseListener(mapControl, workspaceTree));
        mapControl.addMouseWheelListener(new MouseAdapter() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                super.mouseWheelMoved(e);
                double scale = mapControl.getMap().getScale();
                BigDecimal bigDecimal = new BigDecimal(1 / scale);
                bigDecimal = bigDecimal.setScale(4, RoundingMode.HALF_UP);
                mapScaledLbl.setText("  1 : " + bigDecimal.toString());
            }
        });
        mapControl.addTrackedListener(trackedEvent -> {
            com.supermap.ui.Action mapAction = mapControl.getAction();
            Map map = mapControl.getMap();
            TrackingLayer trackingLayer = map.getTrackingLayer();
            trackingLayer.clear();

            // 点
            if (mapAction.equals(com.supermap.ui.Action.CREATEPOINT)) {
                if (Helper.isEditablePointLayer(map.getLayers())) {
                    GeoPoint geoPoint = (GeoPoint) trackedEvent.getGeometry();
                    GeoStyle geoStyle = geoPoint.getStyle();
                    if (geoStyle == null) {
                        geoStyle = new GeoStyle();
                    }
                    geoStyle.setLineColor(Color.RED);
                    geoStyle.setFillForeColor(Color.RED);
                    geoStyle.setFillBackColor(Color.RED);
                    geoStyle.setMarkerSize(new Size2D(12, 12));
                    geoPoint.setStyle(geoStyle);
                    trackingLayer.add(geoPoint, "Point");
                    map.refresh();
                }
            }
            // 线
            else if (mapAction.equals(com.supermap.ui.Action.CREATELINE) || mapAction.equals(com.supermap.ui.Action.CREATEPOLYLINE)) {
                if (Helper.isEditableLineLayer(map.getLayers())) {
                    GeoLine geoLine = (GeoLine) trackedEvent.getGeometry();
                    GeoStyle geoStyle = geoLine.getStyle();
                    if (geoStyle == null) {
                        geoStyle = new GeoStyle();
                    }
                    geoStyle.setLineColor(Color.RED);
                    geoStyle.setLineWidth(2);
                    geoLine.setStyle(geoStyle);
                    trackingLayer.add(geoLine, "Line");
                    map.refresh();
                }
            }
            // 面
            else if (mapAction.equals(com.supermap.ui.Action.CREATEPOLYGON) || mapAction.equals(com.supermap.ui.Action.CREATERECTANGLE)
                    || mapAction.equals(com.supermap.ui.Action.CREATE_ROUND_RECTANGLE) || mapAction.equals(com.supermap.ui.Action.CREATECIRCLE)) {
                if (Helper.isEditablePolygonLayer(map.getLayers())) {
                    GeoRegion geoRegion = (GeoRegion) trackedEvent.getGeometry();
                    GeoStyle geoStyle = geoRegion.getStyle();
                    if (geoStyle == null) {
                        geoStyle = new GeoStyle();
                    }
                    geoStyle.setFillForeColor(Color.GREEN);
                    geoStyle.setFillBackColor(Color.RED);
                    geoRegion.setStyle(geoStyle);
                    trackingLayer.add(geoRegion, "Polygon");
                    map.refresh();
                }
            }
            // 文本
            else if (mapAction.equals(com.supermap.ui.Action.CREATETEXT)) {
                if (Helper.isEditableTextLayer(map.getLayers())) {
                    InputNameDialog createTextDialog = new InputNameDialog((Frame) mapControl.getRootPane().getParent(), "创建文本对象", true);
                    createTextDialog.setVisible(true);
                    String inputText = createTextDialog.getInputText();
                    createTextDialog.dispose();

                    GeoText geoText = (GeoText) trackedEvent.getGeometry();
                    TextPart textPart = geoText.getPart(0);
                    textPart.setText(inputText);
                    map.refresh();
                }
            }
            // 沿线文本
            else if (mapAction.equals(Action.CREATE_ALONG_LINE_TEXT)) {
                if (Helper.isEditableTextLayer(map.getLayers())) {
                    InputNameDialog createAlongLineTextDialog = new InputNameDialog((Frame) mapControl.getRootPane().getParent(), "创建沿线文本对象", true);
                    createAlongLineTextDialog.setVisible(true);
                    String inputText = createAlongLineTextDialog.getInputText();
                    createAlongLineTextDialog.dispose();

                    GeoCompound geoCompound = (GeoCompound) trackedEvent.getGeometry();
                    GeoText geoText = (GeoText) geoCompound.getPart(0);
                    TextPart textPart = geoText.getPart(0);
                    textPart.setText(inputText);
                    map.refresh();
                }
            }
        });
        Map map = mapControl.getMap();
        map.setAntialias(true);
        mainPane.addTab(mapName, mapControl);
        return mapControl;
    }

    public static SceneControl createSceneControl(String sceneName, JTabbedPane mainPane, WorkspaceTree workspaceTree) {
        if (sceneName == null || sceneName.equals(AttrConsts.EMPTY)) {
            Component[] components = mainPane.getComponents();
            sceneName = "未命名场景";
            if (components != null && components.length > 0) {
                int sceneCount = 0;
                for (Component component : components) {
                    if (component instanceof SceneControl) {
                        sceneCount++;
                    }
                }
                if (sceneCount > 0) {
                    sceneName = sceneName + "_" + sceneCount;
                }
            }
        }
        SceneControl sceneControl = new SceneControl();
        mainPane.addTab(sceneName, sceneControl);
        Scene scene = sceneControl.getScene();
        scene.setWorkspace(workspaceTree.getWorkspace());
        return sceneControl;
    }

    public static void addDatasetToNewMap(Dataset dataset, MainFrame mainFrame) {
        SwingUtilities.invokeLater(() -> {
            String mapTabName = dataset.getName() + AttrConsts.AT + dataset.getDatasource().getAlias();
            MapControl mapControl = Helper.createMapControl(mapTabName, mainFrame.getMainPane(), mainFrame.getWorkspaceTree(), mainFrame.getMapScaledLabel());
            mainFrame.getMainPane().setSelectedComponent(mapControl);
            Map map = mapControl.getMap();
            map.getLayers().add(dataset, true);
            createLayersTree(mainFrame, map);
            updateComponentsEnabled(new Component[]{mainFrame.objectOperateMenu, mainFrame.transportationMenu}, true);
        });
    }

    public static void addDatasetToNewScene(Dataset dataset, MainFrame mainFrame) {
        boolean isAddToTerrainLayers = false;
        boolean isAddToSceneLayers = true;
        if (dataset instanceof DatasetGrid) {
            DatasetGridAddToSceneDialog datasetGridAddToSceneDialog = new DatasetGridAddToSceneDialog(mainFrame, "将影像添加到三维场景", true, dataset.getName());
            datasetGridAddToSceneDialog.setVisible(true);
            isAddToTerrainLayers = datasetGridAddToSceneDialog.isAddToTerrainLayers();
            isAddToSceneLayers = datasetGridAddToSceneDialog.isAddToSceneLayers();
            datasetGridAddToSceneDialog.dispose();
            if (!isAddToTerrainLayers && !isAddToSceneLayers) {
                return;
            }
        }

        boolean finalIsAddToTerrainLayers = isAddToTerrainLayers;
        boolean finalIsAddToSceneLayers = isAddToSceneLayers;
        SwingUtilities.invokeLater(() -> {
            String sceneTabName = dataset.getName() + AttrConsts.AT + dataset.getDatasource().getAlias();
            SceneControl sceneControl = createSceneControl(sceneTabName, mainFrame.getMainPane(), mainFrame.getWorkspaceTree());
            Scene scene = sceneControl.getScene();
            mainFrame.getMainPane().setSelectedComponent(sceneControl);
            if (finalIsAddToTerrainLayers) {
                scene.getTerrainLayers().add((DatasetGrid) dataset, true);
            }
            if (finalIsAddToSceneLayers) {
                Layer3DSetting layer3DSetting = new Layer3DSettingVector();
                if (dataset instanceof DatasetGrid) {
                    layer3DSetting = new Layer3DSettingGrid();
                } else if (dataset instanceof DatasetImage) {
                    layer3DSetting = new Layer3DSettingImage();
                }
                scene.getLayers().add(dataset, layer3DSetting, true);
            }
            createLayer3DsTree(mainFrame, scene);
            updateComponentsEnabled(new Component[]{mainFrame.styleSettingMenu, mainFrame.space3DAnalystMenu}, true);
        });
    }

    public static LayersTree createLayersTree(MainFrame mainFrame, Map map) {
        LayersTree layersTree = new LayersTree(map);
        layersTree.addMouseListener(new LayersTreeMouseListener(layersTree, mainFrame.getDataPane(), mainFrame.getSettingPane()));
        mainFrame.getTreeSplitPane().setBottomComponent(new JScrollPane(layersTree));
        return layersTree;
    }

    public static Layer3DsTree createLayer3DsTree(MainFrame mainFrame, Scene scene) {
        Layer3DsTree layer3DsTree = new Layer3DsTree(scene);
        layer3DsTree.addMouseListener(new Layer3DsTreeMouseListener(layer3DsTree));
        mainFrame.getTreeSplitPane().setBottomComponent(new JScrollPane(layer3DsTree));
        return layer3DsTree;
    }

    public static void showDatasetVectorsComparison(String title, Dataset srcDataset, Dataset tarDataset, MainFrame mainFrame) {
        SwingUtilities.invokeLater(() -> {
            Workspace workspace = mainFrame.getWorkspaceTree().getWorkspace();
            JSplitPane coordSysTranslatorSplitPanel = new JSplitPane();
            coordSysTranslatorSplitPanel.setResizeWeight(0.5);

            MapControl srcMapControl = new MapControl(workspace);
            coordSysTranslatorSplitPanel.setLeftComponent(srcMapControl);
            srcMapControl.getMap().getLayers().add(srcDataset, createDefaultLayerSetting(srcDataset), true);

            MapControl coordSysTranslatorMapControl = new MapControl(workspace);
            coordSysTranslatorSplitPanel.setRightComponent(coordSysTranslatorMapControl);
            coordSysTranslatorMapControl.getMap().getLayers().add(tarDataset, createDefaultLayerSetting(tarDataset), true);

            JTabbedPane mainPane = mainFrame.getMainPane();
            mainPane.addTab(title, coordSysTranslatorSplitPanel);
            mainPane.setSelectedComponent(coordSysTranslatorSplitPanel);
        });
    }

    private static LayerSetting createDefaultLayerSetting(Dataset dataset) {
        LayerSetting layerSetting = null;
        if (dataset instanceof DatasetVector) {
            layerSetting = new LayerSettingVector();
        } else if (dataset instanceof DatasetGrid) {
            layerSetting = new LayerSettingGrid();
        } else if (dataset instanceof DatasetImage) {
            layerSetting = new LayerSettingImage();
        }
        return layerSetting;
    }

    //随机颜色
    public static Color randomColor() {
        Random mRandom = new Random();
        StringBuilder mBuilder = new StringBuilder(); //使用之前首先清空内容
        String haxString;
        for (int i = 0; i < 3; i++) {
            haxString = Integer.toHexString(mRandom.nextInt(0xFF));
            if (haxString.length() == 1) {
                haxString = "0" + haxString;
            }
            mBuilder.append(haxString);
        }
        return Color.decode("#" + mBuilder.toString());
    }
}
